/*   Shotscreens
 *
 *   Copyright (C) 2011, Viatcheslav Gachkaylo <vgachkaylo@gmail.com>
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "fullscreenwidget.h"

#include <Cocoa/Cocoa.h>

#include "CGSPrivate.h"

@interface NSApplication (ContextID)
- (int) contextID;
@end

static QString qt_mac_NSStringToQString(const NSString *nsstr)
{
    NSRange range;
    range.location = 0;
    range.length = [nsstr length];

    unichar *chars = new unichar[range.length];
    [nsstr getCharacters:chars range:range];
    QString result = QString::fromUtf16(chars, range.length);
    delete[] chars;
    return result;
}

static void WindowListApplierFunction(const void *inputDictionary, void *context) {
    NSDictionary *entry = (NSDictionary*)inputDictionary;
    QList<FullscreenWidget::WindowInfo> *dataList =
            (QList<FullscreenWidget::WindowInfo>*)context;

    int sharingState = [[entry objectForKey:(id)kCGWindowSharingState] intValue];
    if(sharingState != kCGWindowSharingNone) {
        FullscreenWidget::WindowInfo data;

        // Grab the application name, but since it's optional we need to check before we can use it.
        NSString *applicationName = [entry objectForKey:(id)kCGWindowOwnerName];
        if (applicationName != NULL)
        {
            // PID is required so we assume it's present.
            //NSString *nameAndPID = [NSString stringWithFormat:@"%@ (%@)", applicationName, [entry objectForKey:(id)kCGWindowOwnerPID]];
            //[outputEntry setObject:nameAndPID forKey:kAppNameKey];
            data.name = qt_mac_NSStringToQString(applicationName);
        }
        else
        {
             // The application name was not provided, so we use a fake application name to designate this.
             // PID is required so we assume it's present.
             //NSString *nameAndPID = [NSString stringWithFormat:@"((unknown)) (%@)", [entry objectForKey:(id)kCGWindowOwnerPID]];
             //[outputEntry setObject:nameAndPID forKey:kAppNameKey];
            data.name = QString::fromAscii("(unknown)");
        }

        // Grab the Window Bounds, it's a dictionary in the array, but we want to display it as a string
        CGRect bounds;
        CGRectMakeWithDictionaryRepresentation(
                (CFDictionaryRef)[entry objectForKey:(id)kCGWindowBounds],
                &bounds);
        data.frame = QRect(bounds.origin.x, bounds.origin.y,
                           bounds.size.width, bounds.size.height);
        //NSString *originString = [NSString stringWithFormat:@"%.0f/%.0f", bounds.origin.x, bounds.origin.y];
        //[outputEntry setObject:originString forKey:kWindowOriginKey];
        //NSString *sizeString = [NSString stringWithFormat:@"%.0f*%.0f", bounds.size.width, bounds.size.height];
        //[outputEntry setObject:sizeString forKey:kWindowSizeKey];

        // Grab the Window ID & Window Level. Both are required, so just copy from one to the other
        data.id     = (WId)[[entry objectForKey:(id)kCGWindowNumber] intValue];
        data.layer  = [[entry objectForKey:(id)kCGWindowLayer] intValue];

        dataList->push_back(data);
    }
}

bool FullscreenWidget::updateWindowsInfo() {
    CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly,
                                                       kCGNullWindowID);
    this->windowsInfo.clear();
    CFArrayApplyFunction(windowList,
                         CFRangeMake(0, CFArrayGetCount(windowList)),
                         &WindowListApplierFunction, &this->windowsInfo);
    CFRelease(windowList);

    return true;
}

int FullscreenWidget::getWindowIndexAtPoint(const QPoint &pt) {
    NSPoint nspt;
    nspt.x = pt.x();
    nspt.y = pt.y();

    for (int i = 0; i < windowsInfo.length(); ++i) {
        if (windowsInfo[i].frame.contains(pt)) {
            if ((windowsInfo[i].name == "Dock" &&
                // FIXME: magic number check ---v
                windowsInfo[i].frame.top() == 22 && windowsInfo[i].frame.left() == 0) ||
                windowsInfo[i].name == "SystemUIServer") {
                    continue;
            } else
                return i;
        }
    }

    return -1;
}

//void FullscreenWidget::placeInFrontOf(int index) {
//    NSView *thisView = (NSView*)this->winId();
//    NSWindow *thisWindow = [thisView window];
//    [thisWindow orderWindow:NSWindowAbove
//                relativeTo:(NSInteger)windowsInfo[index].id];
//}

void FullscreenWidget::hilightWindowAt(int index) {
    hilighter.setGeometry(windowsInfo[index].frame);

    // grab a context ID
    int cid = (int)[NSApp contextID];
    NSView *hilighterView = (NSView*)hilighter.winId();
    NSWindow *hilighterWindow = [hilighterView window];

    [hilighterWindow setLevel:windowsInfo[index].layer];

    CGSOrderWindow(cid, (CGSWindow)[hilighterWindow windowNumber],
            kCGSOrderAbove, (CGSWindow)windowsInfo[index].id);
}

QPixmap FullscreenWidget::getQPixmapForWindowIndex(int index) {
    CGRect imageBounds;
    imageBounds.origin.x = windowsInfo[index].frame.x();
    imageBounds.origin.y = windowsInfo[index].frame.y();
    imageBounds.size.width = windowsInfo[index].frame.width();
    imageBounds.size.height = windowsInfo[index].frame.height();

    CGImageRef windowImage = CGWindowListCreateImage(imageBounds,
                                                     kCGWindowListOptionIncludingWindow,
                                                     (CGWindowID)windowsInfo[index].id,
                                                     kCGWindowImageDefault);
    QPixmap res = QPixmap::fromMacCGImageRef(windowImage);
    qDebug("QPixmap dimensions: %d, %d", res.width(), res.height());
    CGImageRelease(windowImage);

    return res;
}
